﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SpaceMan.Physics
{
    class MAN_PhysicsManager
    {

        Dictionary<string, PHY_Base> Bodies;
        Dictionary<PHY_Base, string> inverseBodies;
        
        public MAN_PhysicsManager()
        {
            Bodies = new Dictionary<string, PHY_Base>();
            inverseBodies = new Dictionary<PHY_Base, string>();
        }

        public void Update()
        {
            clampPositions();

            for (int j = 0; j < 2; j++)
            {
                    foreach (PHY_Base body in Bodies.Values)
                    {

                            if (body.GravityWell != null)
                            {
                                foreach (PHY_Base attractBody in Bodies.Values)
                                {
                                    if (attractBody != body)
                                    {
                                        body.GravityWell.attract(attractBody);
                                    }
                                }
                            }


                            body.Update();

                            bool correctPositions = false;

                            if (body.Collider != null)
                            {
                                for (int i = 0; i < body.Collider.Count; i++)
                                {
                                    if (body.Collider[i].hitSomething)
                                    {
                                        correctPositions = true;
                                        body.Collider[i].hitSomething = false;
                                        if (body.Collider[i].CollisionAxis == HitDirection.Horizontal)
                                        {
                                            body.currentState.V.X = 0;
                                        }

                                        else if (body.Collider[i].CollisionAxis == HitDirection.Vertical)
                                        {
                                            body.currentState.V.Y = 0;
                                        }

                                        body.currentState.Pos = body.Collider[i].Position;

                                        i = 0;

                                    }

                                    if (correctPositions)
                                    {
                                        body.Collider[i].Position = body.currentState.Pos + body.Collider[i].Offset;
                                    }

                                }
                            }
                }
            }

            checkHurtCollision();

            for (int i = Bodies.Count - 1; i >= 0; i--)
            {
                if (Bodies.ElementAt(i).Value.MarkedForDeletion == true)
                {
                    Bodies.Remove(Bodies.ElementAt(i).Key);
                }
            }

            
        }

        void clampPositions()
        {
            foreach (PHY_Base body in Bodies.Values)
            {
                if (body.Collider != null && !body.isStatic)
                {
                    foreach (PHY_Collider Collider in body.Collider)
                    {
                        if (Collider.CollisionType == ColliderType.Rectangle && !(Collider is PHY_Hurt))
                        {
                            Rectangle superRectWidth = new Rectangle(int.MinValue / 2, Collider.Rectangle.Y, int.MaxValue, Collider.Rectangle.Height);
                            Rectangle superRectHeight = new Rectangle(Collider.Rectangle.X, int.MinValue / 2, Collider.Rectangle.Width, int.MaxValue);

                            foreach (PHY_Base body1 in Bodies.Values)
                            {
                                if (body1 != body && body1.Collider != null)
                                {
                                    foreach (PHY_Collider Collider1 in body1.Collider)
                                    {
                                        if (!(Collider1 is PHY_Hurt))
                                        {
                                            if (superRectHeight.Intersects(Collider1.Rectangle))
                                            {
                                                //CLAMP ANY AND ALL VERTICAL POSITIONS
                                                if (Collider1.Rectangle.Center.Y + body1.currentState.Pos.Y < Collider.Rectangle.Center.Y + body.currentState.Pos.Y)
                                                {
                                                    Collider.Clamp(new Vector2(float.MinValue, Collider1.Rectangle.Bottom - Collider.Offset.Y), new Vector2(float.MaxValue, float.MaxValue));
                                                }

                                                else if (Collider1.Rectangle.Center.Y + body1.currentState.Pos.Y > Collider.Rectangle.Center.Y + body.currentState.Pos.Y)
                                                {
                                                    Collider.Clamp(new Vector2(float.MinValue, float.MinValue), new Vector2(float.MaxValue, Collider1.Rectangle.Top - Collider.Rectangle.Height - Collider.Offset.Y));
                                                }
                                            }

                                            if (superRectWidth.Intersects(Collider1.Rectangle))
                                            {
                                                //CLAMP ALL HORIZONTAL
                                                if (Collider1.Rectangle.Center.X + body1.currentState.Pos.X < Collider.Rectangle.Center.X + body.currentState.Pos.X)
                                                {
                                                    Collider.Clamp(new Vector2(Collider1.Rectangle.Right - Collider.Offset.X, float.MinValue), new Vector2(float.MaxValue, float.MaxValue));
                                                }

                                                else if (Collider1.Rectangle.Center.X + body1.currentState.Pos.X > Collider.Rectangle.Center.X + body.currentState.Pos.X)
                                                {
                                                    Collider.Clamp(new Vector2(float.MinValue, float.MinValue), new Vector2(Collider1.Rectangle.Left - Collider.Rectangle.Width - Collider.Offset.X, float.MaxValue));
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public void addBody(PHY_Base Body, string Ownername)
        {
            int number = 0;
            while (true)
            {
                if (!Bodies.ContainsKey(Ownername + number))
                {
                    Bodies.Add(Ownername + number, Body);
                    Body.ParentMe = Parent;
                    break;
                }
                number++;
            }

            inverseBodies.Clear();
            for (int i = 0; i < Bodies.Count; i++)
            {
                inverseBodies.Add(Bodies.ElementAt(i).Value, Bodies.ElementAt(i).Key);
            }
        }

        void checkHurtCollision()
        {
            foreach (PHY_Base Body in Bodies.Values)
            {
                if (Body.Collider != null)
                {
                    foreach (PHY_Collider collider in Body.Collider)
                    {
                        if (collider is PHY_Hurt)
                        {
                            PHY_Hurt hurt = (PHY_Hurt)collider;
                            Rectangle hurtRectangle = new Rectangle(hurt.Rectangle.X - 1, hurt.Rectangle.Y - 1, hurt.Rectangle.Width + 1, hurt.Rectangle.Height + 1);
                            

                            
                            foreach (PHY_Base Body1 in Bodies.Values)
                            {

                                if (Body != Body1 && Body1.Collider != null)
                                {
                                    foreach (PHY_Collider collider1 in Body1.Collider)
                                    {
                                        if (hurtRectangle.Intersects(collider1.Rectangle) && !(collider1 is PHY_Hurt) && collider1.damageAffinity != hurt.damageAffinity)
                                        {
                                            collider1.HurtMe(hurt.Damage, hurt.damageAffinity);
                                            hurt.DidDamage();
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        

        //public void removeBody(PHY_Base Body)
        //{
        //    if (Bodies.ContainsValue(Body))
        //    {
        //        Bodies.Remove(inverseBodies[Body]);
        //    }

        //    inverseBodies.Clear();
        //    for (int i = 0; i < Bodies.Count; i++)
        //    {
        //        inverseBodies.Add(Bodies.ElementAt(i).Value, Bodies.ElementAt(i).Key);
        //    }
        //}

        public void Parent(PHY_Base Parent, string ChildName, bool LockPosition)
        {
            if (Bodies.ContainsKey(ChildName))
            {
                if(!Parent.children.Contains(Bodies[ChildName]))
                    Bodies[ChildName].Parent(Parent, LockPosition);
            }
        }
    }
}
